#pragma once
#include <iostream>

template <class T> class MyStack2
{
	class Node
	{
	public:
		Node* pNext;		//��������� �� ��������� �������
		T m_Data;

		//������:
		Node(): pNext(nullptr), m_Data() {}
		Node(Node *prev, const T& data):m_Data(data) {this->pNext = prev->pNext; prev->pNext = this;}//new Node �������������� � ������.
		//~Node() { }
	};
		
	Node* Head;
	size_t exist;
	
public:
	
	MyStack2():Head(new Node),exist(0) {};// ���������� ����������
	MyStack2(const MyStack2& other);
	MyStack2(MyStack2&& other);
	MyStack2& operator=(const MyStack2& other);
	MyStack2& operator=(MyStack2&& other);
	~MyStack2();


	void Push(const T& =T());
	T Pop();

	void Print();
	void rPrint();
};

template<class T>
inline MyStack2<T>::MyStack2(const MyStack2& other)
	:Head(new Node), exist(other.exist)
{
	
	//for (size_t it = other.exist; it > 0; it--)
	//{
	//	Node* tmp = other.Head->pNext;
	//	Node* tmpPrev = other.Head;

	//	/*for (size_t i = 0; i < it; i++)
	//	{
	//		tmpPrev = tmpPrev->pNext;
	//		tmp = tmp->pNext;
	//	}
	//	Push(tmpPrev->m_Data);*/
	//}

	Node* tmp = other.Head->pNext;
	Node* tmpPrev = Head;

	for (size_t it = other.exist; it > 0; it--)
	{		
		tmpPrev = new Node(tmpPrev, tmp->m_Data);
		tmp = tmp->pNext;
	}
}

template<class T>
inline MyStack2<T>::MyStack2(MyStack2&& other)
	:Head (other.Head), exist(other.exist)
{
	other.Head = new Node;
	other.exist = 0;
}

template<class T>
inline MyStack2<T>& MyStack2<T>::operator=(const MyStack2& other)
{
	if (&other != this)
	{
		if (exist >= other.exist)
		{
			while (exist!= other.exist)
			{
				Pop();
			}

			if (!exist) { return *this; }
		}

		Node* tmpOther = other.Head->pNext;
		Node* tmpThis = Head->pNext;

		if (exist < other.exist)
		{
			for (size_t i = 0; i < other.exist - exist; i++)
			{
				tmpOther = tmpOther->pNext;
			}
		}

		for (size_t it = 0; it < exist; it++)
		{			
			tmpThis->m_Data = tmpOther->m_Data;
			tmpThis = tmpThis->pNext;
			tmpOther= tmpOther->pNext;
		}


		for (size_t it = other.exist - exist; it > 0; it--)
		{
			Node* tmpPrev = other.Head;
			tmpOther = tmpPrev->pNext;

			for (size_t i = 0; i < it; i++)
			{
				tmpPrev = tmpPrev->pNext;
				tmpOther = tmpOther->pNext;
			}			
			Push(tmpPrev->m_Data);
		}
	}
	return *this;
}

template<class T>
inline MyStack2<T>::~MyStack2()
{
	while (exist != 0)
	{
		Node* del = Head->pNext;
		Head->pNext = del->pNext;
		delete del;
		exist--;
	}
	delete Head;
}

template<class T>
inline void MyStack2<T>::Push(const T& Data)
{	
	new Node(Head,Data);
	exist++;
}

template<class T>
inline T MyStack2<T>::Pop()
{
	if (exist != 0)
	{
		T tmpT = Head->pNext->m_Data;//���� �� ����� �� ���������� � ������ ������ � ���������� ������ �� ������ � �� �� ��������?
		Node* tmpN = Head->pNext;
		Head->pNext = tmpN->pNext;
		delete tmpN;
		exist--;
		return tmpT;
	}
	throw std::out_of_range("No Data");
}

template<class T>
inline void MyStack2<T>::Print()
{
	if (exist == 0) { std::cout << "Empty list" << std::endl; return; }

	Node* tmp = Head->pNext;
	for (size_t i = 0; i < exist; i++)
	{		
		std::cout << tmp->m_Data << ' ';
		tmp = tmp->pNext;
	}
	std::cout << std::endl;
}

template<class T>
inline void MyStack2<T>::rPrint()
{
	if (exist==0){ std::cout <<"Empty list" << std::endl; return;}

	for (size_t it = exist; it > 0; it--)
	{
		Node* tmp = Head->pNext;
		Node* tmpPrev = Head;

		for (size_t i = 0; i < it; i++)
		{
			tmpPrev = tmpPrev->pNext;
			tmp = tmp->pNext;
		}

		std::cout << tmpPrev->m_Data << ' ';
	}
	
	std::cout << std::endl;
}


